package it.unibo.iss.domotica.com;
import java.util.Vector;
import java.util.Iterator;
import it.unibo.is.interfaces.*;
import it.unibo.is.common.IS09Util;
import it.unibo.is.interfaces.platforms.*;
import it.unibo.platform.lindaLike.LindaLike;
import it.unibo.contact.platform.InteractPolicy;
import it.unibo.contact.platform.PlatformContact;

/*
 *  Abstract class Subject
 */
public abstract class Subject extends Thread {
	private IOutputView view;
	private int curInputTodo = 0;
	private ILindaLike core = LindaLike.getSpace();
	private IMedCl09 support = new PlatformContact();

	public void run(){
		view = null; //OutputViewAbstract.getOutputView();
		try { 
			doJob(); 
			terminate();
		} catch (Exception e) {
			showMsg("ERROR " + e.getMessage());
		}
	}

	abstract protected void doJob() throws Exception;
	abstract protected void terminate() throws Exception;

	protected boolean isSignal( String msgId ){
		return 

		false;	


	}

	/*
	 * 	Given a list of token-query, removes all unifiable tokens
	 *   or waits
	 */
	protected Vector<IMessage> allInput( Vector<String> msgIds )	throws Exception {
		Vector<String> queryList = new Vector<String>();
		Iterator<String> iter = msgIds.iterator();
		while( iter.hasNext() ){
			String mid = iter.next();
			queryList.add( mid + "(S,"+ mid +", C, N)");
		}
		return support.removeAll(this.getName(), queryList, InteractPolicy.nopolicy());
	}

	/*
	 * 	Given a list of msg-query, selects one available msgId or waits
	 */
	protected IMessage selectOneInput( int LastMsgNum, Vector<IMessage> queries ) throws Exception {
		return LindaLike.getSpace().selectOneFromMany(LastMsgNum, queries);
	}

	/*
	 * 	Given a list of msg-query, selects one available msgId or waits
	 */
	protected String selectInput(Vector<IMessage> manyInput, int lastMsgNum)
	throws Exception {
		String msg = null;
		while ( msg == null) { //no message available
			//---   1)  --- Insert the manyInput request token  --- 
			support.insert(this.getName(), "manyInput", "wait", InteractPolicy.nopolicy());
			//---   2)  --- Check if it exists a input message  ---
			msg = checkSubjectInput(curInputTodo, 0, manyInput, lastMsgNum);
			if( msg == null ){
				//			showMsg(" *** wait " );   
				//---   3) --- Wait until it is possible toRemove the token that says that the space is changed ---
				IMessage mmm = support.remove(this.getName(), "resume"
						+ this.getName(), InteractPolicy.nopolicy());			
				//---   4) --- The shared space is changed with a message that is in the input set --- 
				IMessage newMsg = new Message(mmm.msgContent());
				//			showMsg(" *** resumed " + newMsg );
				//Now we know the msg that has caused the resume. Check if this pertinent and not an answer
				IMessage minp = LindaLike.getSpace().rd(
						0,
						"multiSource( '" + this.getName() + "','" + newMsg.msgId()
						+ "')");
				if (minp != null //it is pertinent (i.e. one of the input expected)
						&& //AND
						(newMsg.getMsgName().equals(
								this.getName() + "_" + newMsg.msgId()) //it is a request
								|| //OR
								newMsg.getMsgName().equals(newMsg.msgId())) //it is a signal
				) {
					msg = checkSubjectInput(curInputTodo, 0, manyInput, lastMsgNum);
					if (msg == null)
						showMsg("PLEONASTIC CHECK " + minp); //should never appear
				}
			}
		}
		return msg;
	}

	/*
	 * 	 Given a list of msg-query, performs a round-robin check
	 *   starting from curInputTodo. If does not find any unifiable
	 *   message returns null
	 */
	protected String checkSubjectInput(int k, int n,
			Vector<IMessage> manyInput, int lastMsgNum) throws Exception {
		IMessage m = null;
		int ns = manyInput.size();
		if (n > ns) {
			curInputTodo = k;
			//no input available on any source 
			return null;
		}
		//n < ns
		if (k <= ns - 1) { //there is some input source to explore going forward
			IMessage qm = manyInput.elementAt(k);
			String queryS = qm.toString();
			//			showMsg("selectInput " + " k="+ k + " n="+ n + " ns="+ ns + " " + queryS + " id=" + qm.msgId() + " lastMsgNum=" + lastMsgNum);
			if (isSignal(qm.msgId())) {
				m = core.rd(lastMsgNum, queryS);
			} else {
				m = core.rd(0, queryS);
			}
			if (m != null) {
				curInputTodo = k + 1;
				return m.msgId();
			} else
				return checkSubjectInput(k + 1, n + 1, manyInput, lastMsgNum);
		} else { //end of manyInput reached. Restart from beginning
			return checkSubjectInput(0, n + 1, manyInput, lastMsgNum);
		}
	}
	/* ==================================
	UTILS
 ================================== */
	public  void showMsg( String m){
		IS09Util.showMsg(view, this.getName() + " " + m );
	}

	public  void showMessage( String comment,  IMessage m){
		if( m != null) {
			String msgEmitter 	= m.msgEmitter();
			String msgId 		= m.msgId();
			String msgContent 	= m.msgContent();
			String msgNum 		= m.msgNum();

			IS09Util.showMsg(view, this.getName() + " " + comment + ":" +
					"msgEmitter="+ msgEmitter  + " msgId="+ msgId +
					" msgContent=" + msgContent + " msgNum=" + msgNum);
		}		  
	}  


}
